package com.supermap.hn.traffic.services;

import com.supermap.analyst.networkanalyst.*;
import com.supermap.data.*;
import com.supermap.hn.traffic.commontype.LimitParameter;
import com.supermap.hn.traffic.commontype.LimitSpeedResult;
import com.supermap.hn.traffic.commontype.Point;
import com.supermap.hn.traffic.config.NetworkConfig;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.MatchQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.env.Environment;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Future;

@Service
public class SSCMatchService {
    private static final Logger log = LogManager.getLogger(LogManager.ROOT_LOGGER_NAME);
    //用来判断是否返回全部数据
    private Workspace m_workspace;
    //矢量数据集类
    private DatasetVector network_dataset;
    private DatasetVector matchResult_dataset;
    private MapMatching mapMatchingSSC;
    private ArrayList<TrackPoint> trackPointList;
    //SSC数据环境类
    private SSCPathAnalystSetting sscPathAnalystSetting;

    private ConcurrentHashMap<String,MapMatching> vehicleNoMap = new ConcurrentHashMap<String,MapMatching>() ;

    int num = 0;

    @Value("${elasticsearch.searchIndex}")
    private String SEARCH_INDEX;

    @Autowired
    private final NetworkConfig networkConfig;
    @Autowired
    private RestHighLevelClient restHighLevelClient;
    @Value("${supermapMatch.debug}")
    private boolean debug;
    @Autowired
    private Environment env;

    public SSCMatchService(NetworkConfig networkConfig, @Value("${supermapMatch.debug}") Boolean debug) {
        log.info("开始初始化网络服务#######################");
        this.networkConfig = networkConfig;
        //打开工作空间
        m_workspace = new Workspace();
        WorkspaceConnectionInfo workspaceConnectionInfo = new WorkspaceConnectionInfo(this.networkConfig.getWorkspacePath());
        m_workspace.open(workspaceConnectionInfo);

        //获取网络数据集
        String network_datasourceName = this.networkConfig.getDatasourceName();
        String network_datasetName = this.networkConfig.getDatasetName();
        Datasource network_datasource = m_workspace.getDatasources().get(network_datasourceName);
        network_dataset = (DatasetVector) m_workspace.getDatasources().get(network_datasourceName).getDatasets().get(network_datasetName);
        Datasource result_datasource = m_workspace.getDatasources().get(this.networkConfig.getResdatasourceName());
        if (debug) {
            //调试结果数据集
            String matchResult_datasetName = String.format("matchResult_" + new SimpleDateFormat("HH_mm_ss").format(new Date()).toString());
            log.info("开启debug模式，结果数据集:" + matchResult_datasetName);
            // 设置矢量数据集的信息
            DatasetVectorInfo datasetVectorInfo = new DatasetVectorInfo();
            datasetVectorInfo.setType(DatasetType.LINE);
            datasetVectorInfo.setEncodeType(EncodeType.NONE);
            datasetVectorInfo.setFileCache(true);
            datasetVectorInfo.setName(matchResult_datasetName);

            //FieldInfos fieldinfos = network_dataset.getFieldInfos();
            matchResult_dataset = (DatasetVector) result_datasource.getDatasets().create(datasetVectorInfo);

        }
        trackPointList = new ArrayList<TrackPoint>();
        //SSC数据环境类
        sscPathAnalystSetting = new SSCPathAnalystSetting();
        sscPathAnalystSetting.setNetworkDataset(network_dataset);
        log.info("加载网络数据集:" + network_dataset.getName());
        sscPathAnalystSetting.setSSCFilePath(this.networkConfig.getSscFilePath());
        log.info("加载SSC文件:" + this.networkConfig.getSscFilePath());
        //设置地图匹配对象
        mapMatchingSSC = getMapMatching(sscPathAnalystSetting);
        log.info("网络服务初始化完成");
    }

    public MapMatching getMapMatching(SSCPathAnalystSetting sscPathAnalystSetting) {
        MapMatching mapMatchingSSC = new MapMatching();
        mapMatchingSSC.setPathAnalystSetting(sscPathAnalystSetting);
        mapMatchingSSC.setMeasurementError(this.networkConfig.getMeasurementError());
        mapMatchingSSC.setMaxLimitedSpeed(this.networkConfig.getMaxLimitedSpeed());
        return mapMatchingSSC;
    }

    /**
     * 获取道路限速值信息
     *
     * @param limitParam
     * @return
     */
   // @Async("asyncServiceExecutor")
    public LimitSpeedResult getSpeedLimit(LimitParameter limitParam) throws IOException {
        log.info("当前线程ID： " + Thread.currentThread().getId());
        log.info("当前位数： " + num++);
        LimitSpeedResult result = new LimitSpeedResult();
        //MapMatching mapMatchingSSC = getMapMatching(sscPathAnalystSetting);
        if (limitParam != null && limitParam.point != null) {
            //获取轨迹点
            TrackPoint trackPoint = getTrackPoint(limitParam);
            if (debug) {
                log.info(limitParam.vehicleNo + " 开始匹配:[" + limitParam.point.x + "," + limitParam.point.y + "," + limitParam.point.time + "]");
            }
            MapMatchingLikelyResult[] mapMatchingResults = mapMatchingSSC.match(trackPoint, false);

            if (mapMatchingResults != null && mapMatchingResults.length > 0) {
                if (debug) {
                    log.info("匹配到路线数量： " + mapMatchingResults.length);
                }
                //循环遍历获取分数最大值
                double maxProbability = mapMatchingResults[0].getProbability();
                int maxIndex = 0;
                for (int i = 1; i < mapMatchingResults.length; i++) {
                    if (mapMatchingResults[i].getProbability() > maxProbability) {
                        maxIndex = i;
                        maxProbability = mapMatchingResults[i].getProbability();
                    }
                }
                int edgesCount = mapMatchingResults[maxIndex].getEdges().length;
                if (edgesCount > 0) {
                    int edgeID = mapMatchingResults[maxIndex].getEdges()[edgesCount - 1];

                    log.info("匹配到的弧段id为：  " + edgeID);
                    // 返回空间查询中的搜索对象
                    Recordset recordset = network_dataset.query(new int[]{edgeID}, "EdgeID", CursorType.STATIC);
                    if (!recordset.isEmpty()) {
                        log.info("PathName:" + recordset.getFieldValue("PathName"));
                        log.info("SpdLmtS2E:" + recordset.getFieldValue("SpdLmtS2E"));
                        log.info("SpdLmtE2S:" + recordset.getFieldValue("SpdLmtE2S"));

                        result.setName(recordset.getFieldValue("PathName").toString());
                        if (!recordset.getFieldValue("SpdLmtS2E").toString().isEmpty()) {
                            result.setUpSpeed(Integer.parseInt(recordset.getFieldValue("SpdLmtS2E").toString()));
                        }
                        if (!recordset.getFieldValue("SpdLmtE2S").toString().isEmpty()) {
                            result.setDownSpeed(Integer.parseInt(recordset.getFieldValue("SpdLmtE2S").toString()));
                        }
                        //将轨迹线追加到结果数据集
//                        boolean append = matchResult_dataset.append(recordset);
//                        log.info("是否写入成功： " + append);
                        recordset.close();
                        recordset.dispose();

                    }
                    recordset.close();
                    recordset.dispose();
                } else {
                    log.info("没有匹配到弧段id");
                }
            }
        }
        return result;

    }

    private TrackPoint getTrackPoint(LimitParameter limitParam) {
        Point gpsPoint = limitParam.point;
        TrackPoint trackPoint = new TrackPoint();
        Point2D gpsPoint_gcj02 = new Point2D(gpsPoint.x, gpsPoint.y);
        trackPoint.setPoint(gpsPoint_gcj02);
        Date date = new Date(gpsPoint.time);

        trackPoint.setTime(date);
        return trackPoint;
    }


    //异步执行
    @Async("asyncServiceExecutor")
    public Future<LimitSpeedResult> asynGetSpeedLimit(LimitParameter limitParam) throws IOException {

        log.info("当前线程ID： " + Thread.currentThread().getId());
        LimitSpeedResult result = new LimitSpeedResult();
        MapMatching mapMatchingSSC = getMapMatching(sscPathAnalystSetting);
        if (limitParam != null && limitParam.point != null) {
            //获取轨迹点
            TrackPoint trackPoint = getTrackPoint(limitParam);
            if (debug) {
                log.info(limitParam.vehicleNo + " 开始匹配:[" + limitParam.point.x + "," + limitParam.point.y + "," + limitParam.point.time + "]");
            }
            MapMatchingLikelyResult[] mapMatchingResults = mapMatchingSSC.match(trackPoint, false);

            if (mapMatchingResults != null && mapMatchingResults.length > 0) {
                if (debug) {
                    log.info("匹配到路线数量： " + mapMatchingResults.length);
                }
                //循环遍历获取分数最大值
                double maxProbability = mapMatchingResults[0].getProbability();
                int maxIndex = 0;
                for (int i = 1; i < mapMatchingResults.length; i++) {
                    if (mapMatchingResults[i].getProbability() > maxProbability) {
                        maxIndex = i;
                        maxProbability = mapMatchingResults[i].getProbability();
                    }
                }
                int edgesCount = mapMatchingResults[maxIndex].getEdges().length;
                if (edgesCount > 0) {
                    int edgeID = mapMatchingResults[maxIndex].getEdges()[edgesCount - 1];

                    log.info("匹配到的弧段id为：  " + edgeID);
                    // 返回空间查询中的搜索对象
                    Recordset recordset = network_dataset.query(new int[]{edgeID}, "EdgeID", CursorType.STATIC);
                    if (!recordset.isEmpty()) {
                        log.info("PathName:" + recordset.getFieldValue("PathName"));
                        log.info("SpdLmtS2E:" + recordset.getFieldValue("SpdLmtS2E"));
                        log.info("SpdLmtE2S:" + recordset.getFieldValue("SpdLmtE2S"));

                        result.setName(recordset.getFieldValue("PathName").toString());
                        if (!recordset.getFieldValue("SpdLmtS2E").toString().isEmpty()) {
                            result.setUpSpeed(Integer.parseInt(recordset.getFieldValue("SpdLmtS2E").toString()));
                        }
                        if (!recordset.getFieldValue("SpdLmtE2S").toString().isEmpty()) {
                            result.setDownSpeed(Integer.parseInt(recordset.getFieldValue("SpdLmtE2S").toString()));
                        }
                        //将轨迹线追加到结果数据集


                        Recordset matchResult_Recordset= matchResult_dataset.getRecordset(false, CursorType.DYNAMIC);
                        GeoLine trackLine = mapMatchingResults[maxIndex].getTrackLine();
                        matchResult_Recordset.edit();
                        //matchResult_Recordset.getBatch().begin();
                        boolean b1 = matchResult_Recordset.addNew(trackLine);
                        log.info("是否写入成功： " + b1);
                        log.info("trackLine: " + trackLine.isEmpty() + "   " + trackLine.getPart(0) );
                        matchResult_Recordset.update();
                        matchResult_Recordset.close();
                        matchResult_Recordset.dispose();

                        matchResult_dataset.close();
                    }
                    recordset.close();
                    recordset.dispose();
                } else {
                    log.info("没有匹配到弧段id");
                }
            }
        }
        return new AsyncResult(result);
    }



    //测试batchMatch
   public LimitSpeedResult batchMatch(LimitParameter limitParam) throws IOException {
       log.info("当前线程ID： " + Thread.currentThread().getId());
       LimitSpeedResult result = new LimitSpeedResult();
       //MapMatching mapMatchingSSC = getMapMatching(sscPathAnalystSetting);
       if (limitParam != null && limitParam.point != null) {
           //获取轨迹点
           ArrayList<TrackPoint> trackPoint = getTrackPointList(limitParam);
           if (debug) {
               log.info(limitParam.vehicleNo + " 开始匹配:[" + limitParam.point.x + "," + limitParam.point.y + "," + limitParam.point.time + "]");
           }
           MapMatchingResult mapMatchingResults = mapMatchingSSC.batchMatch(trackPoint);

               int edgesCount = mapMatchingResults.getEdges().length;
               if (edgesCount > 0) {
                   int edgeID = mapMatchingResults.getEdges()[edgesCount - 1];

                   log.info("匹配到的弧段id为：  " + edgeID);
                   // 返回空间查询中的搜索对象
                   Recordset recordset = network_dataset.query(new int[]{edgeID}, "EdgeID", CursorType.STATIC);
                   if (!recordset.isEmpty()) {
                       log.info("PathName:" + recordset.getFieldValue("PathName"));
                       log.info("SpdLmtS2E:" + recordset.getFieldValue("SpdLmtS2E"));
                       log.info("SpdLmtE2S:" + recordset.getFieldValue("SpdLmtE2S"));

                       result.setName(recordset.getFieldValue("PathName").toString());
                       if (!recordset.getFieldValue("SpdLmtS2E").toString().isEmpty()) {
                           result.setUpSpeed(Integer.parseInt(recordset.getFieldValue("SpdLmtS2E").toString()));
                       }
                       if (!recordset.getFieldValue("SpdLmtE2S").toString().isEmpty()) {
                           result.setDownSpeed(Integer.parseInt(recordset.getFieldValue("SpdLmtE2S").toString()));
                       }
                       //将轨迹线追加到结果数据集
                       boolean append = matchResult_dataset.append(recordset);
                       log.info("是否写入成功： " + append);
                       recordset.close();
                       recordset.dispose();

                   }
                   recordset.close();
                   recordset.dispose();
               } else {
                   log.info("没有匹配到弧段id");
               }
           }

       return result;

   }

    private ArrayList<TrackPoint> getTrackPointList(LimitParameter limitParam) {
        Point gpsPoint = limitParam.point;
        TrackPoint trackPoint = new TrackPoint();
        Point2D gpsPoint_gcj02 = new Point2D(gpsPoint.x, gpsPoint.y);
        trackPoint.setPoint(gpsPoint_gcj02);
        Date date = new Date(gpsPoint.time);
        trackPoint.setTime(date);
        trackPointList.add(trackPoint);
        if(trackPointList.size() > 10){
            trackPointList.remove(0);
        }
        log.info("当前trackPointList长度为： " + trackPointList.size());
        return trackPointList;
    }

    /**
     *  根据车牌获取hashmap中的MapMatching对象
     */
    private MapMatching getMapMatchingByVehicleNo(String vehicleNo) {
        //从map中获取该车牌对应的分析模型
        if(!vehicleNoMap.containsKey(vehicleNo)){
            log.info("创建新的MapMatching对象==============");
            MapMatching mapMatchingSSC = new MapMatching();
            mapMatchingSSC.setPathAnalystSetting(sscPathAnalystSetting);
            mapMatchingSSC.setMeasurementError(this.networkConfig.getMeasurementError());
            mapMatchingSSC.setMaxLimitedSpeed(this.networkConfig.getMaxLimitedSpeed());
            vehicleNoMap.put(vehicleNo, mapMatchingSSC);
            return mapMatchingSSC;
        }else {
            log.info("从hashmap中获取MapMatching对象==============");
            return vehicleNoMap.get(vehicleNo);
        }

    }
    /**
     * 多线程分析
     * @param limitParam
     * @return
     */
    @Async("asyncServiceExecutor")
    public Future<LimitSpeedResult> match(LimitParameter limitParam) {
        log.info("当前线程ID： " + Thread.currentThread().getId());
        LimitSpeedResult result = new LimitSpeedResult();
        MapMatching mapMatchingSSC = getMapMatchingByVehicleNo(limitParam.vehicleNo);
        if (limitParam != null && limitParam.point != null) {
            //获取轨迹点
            TrackPoint trackPoint = getTrackPoint(limitParam);
            if (debug) {
                log.info(limitParam.vehicleNo + " 开始匹配:[" + limitParam.point.x + "," + limitParam.point.y + "," + limitParam.point.time + "]");
            }
            MapMatchingLikelyResult[] mapMatchingResults = mapMatchingSSC.match(trackPoint, false);

            if (mapMatchingResults != null && mapMatchingResults.length > 0) {
                if (debug) {
                    log.info("匹配到路线数量： " + mapMatchingResults.length);
                }
                //循环遍历获取分数最大值
                double maxProbability = mapMatchingResults[0].getProbability();
                int maxIndex = 0;
                for (int i = 1; i < mapMatchingResults.length; i++) {
                    if (mapMatchingResults[i].getProbability() > maxProbability) {
                        maxIndex = i;
                        maxProbability = mapMatchingResults[i].getProbability();
                    }
                }
                int edgesCount = mapMatchingResults[maxIndex].getEdges().length;
                if (edgesCount > 0) {
                    int edgeID = mapMatchingResults[maxIndex].getEdges()[edgesCount - 1];

                    log.info("匹配到的弧段id为：  " + edgeID);
                    // 返回空间查询中的搜索对象
                    result = findRoadByEdgeID(edgeID);
                    log.info("PathName:" +  result.name);
                    log.info("SpdLmtS2E:" + result.upSpeed);
                    log.info("SpdLmtE2S:" + result.downSpeed);
                    //Recordset recordset = network_dataset.query(new int[]{edgeID}, "EdgeID", CursorType.STATIC);
//                    if (!recordset.isEmpty()) {
//                        log.info("PathName:" + recordset.getFieldValue("PathName"));
//                        log.info("SpdLmtS2E:" + recordset.getFieldValue("SpdLmtS2E"));
//                        log.info("SpdLmtE2S:" + recordset.getFieldValue("SpdLmtE2S"));
//
//                        result.setName(recordset.getFieldValue("PathName").toString());
//                        if (!recordset.getFieldValue("SpdLmtS2E").toString().isEmpty()) {
//                            result.setUpSpeed(Integer.parseInt(recordset.getFieldValue("SpdLmtS2E").toString()));
//                        }
//                        if (!recordset.getFieldValue("SpdLmtE2S").toString().isEmpty()) {
//                            result.setDownSpeed(Integer.parseInt(recordset.getFieldValue("SpdLmtE2S").toString()));
//                        }
                        //将轨迹线追加到结果数据集
//                        Recordset matchResult_Recordset= matchResult_dataset.getRecordset(false, CursorType.DYNAMIC);
//                        GeoLine trackLine = mapMatchingResults[maxIndex].getTrackLine();
//                        matchResult_Recordset.edit();
//                        //matchResult_Recordset.getBatch().begin();
//                        boolean b1 = matchResult_Recordset.addNew(trackLine);
//                        log.info("是否写入成功： " + b1);
//                        log.info("trackLine: " + trackLine.isEmpty() + "   " + trackLine.getPart(0) );
//                        matchResult_Recordset.update();
//                        matchResult_Recordset.close();
//                        matchResult_Recordset.dispose();
//                        matchResult_dataset.close();
//                    }
//                    recordset.close();
//                    recordset.dispose();
                } else {
                    log.info("没有匹配到弧段id");
                }
            }
        }
        return new AsyncResult(result);

    }

    //ES查询
    public LimitSpeedResult findRoadByEdgeID(int edgeID) {
        LimitSpeedResult result = new LimitSpeedResult();
        SearchRequest request = new SearchRequest(SEARCH_INDEX);

        MatchQueryBuilder fuzzyQueryBuilder = QueryBuilders.matchQuery("EdgeID", edgeID);
        SearchSourceBuilder builder = new SearchSourceBuilder();
        builder.query(fuzzyQueryBuilder);
        request.source(builder);
        SearchResponse searchResponse = null;
        try {
            searchResponse = restHighLevelClient.search(request, RequestOptions.DEFAULT);
        } catch (IOException e) {
            log.error("查询出错：" + e);
        }
        SearchHits hits = searchResponse.getHits();

        if(hits.totalHits <= 0){
            log.info("未查询到数据...");
            return result;
        }

        SearchHit[] searchHit = hits.getHits();
        SearchHit documentFields = searchHit[0];
        //包装
        if ( documentFields.getSourceAsMap().containsKey("PathName")) {
            result.setName((String) documentFields.getSourceAsMap().get("PathName"));
        }
        if ( documentFields.getSourceAsMap().containsKey("SpdLmtS2E")) {
            result.setUpSpeed(Integer.parseInt(documentFields.getSourceAsMap().get("SpdLmtS2E").toString()));
        }
        if (documentFields.getSourceAsMap().containsKey("SpdLmtE2S")) {
            result.setDownSpeed(Integer.parseInt(documentFields.getSourceAsMap().get("SpdLmtE2S").toString()));
        }

        return result;
    }
}
